﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

using AForge.Video;
using AForge.Video.DirectShow;
using DartDetectorTest1.Detector;


namespace DartDetectorTest1
{
	public delegate void OutputMessageDelegate(string someMessage);
	public partial class Main : Form
	{
		#region Properties
		
		/// <summary>
		/// list of video devices
		/// </summary>
		FilterInfoCollection videoDevices;
 		
 		/// <summary>
 		///	The dartDetector class
 		/// </summary>
		IDartDetector dartDetector;
		
		/// <summary>
		/// Delegate to debug some text
		/// </summary>
		OutputMessageDelegate del;
 		
		#region Statics properties
		
		/// <summary>
		/// statistics length
		/// </summary>
		private const int statLength = 15;
		
		/// <summary>
		/// current statistics index
		/// </summary>
		private int statIndex = 0;
		
		/// <summary>
		/// ready statistics values
		/// </summary>
		private int statReady = 0;
		
		/// <summary>
		/// statistics array 1
		/// </summary>
		private int[] statCount1 = new int[statLength];
		
		/// <summary>
		/// statistics array 2
		/// </summary>
		private int[] statCount2 = new int[statLength];
		
		#endregion
		
		#endregion
		
		/// <summary>
		/// Main entry point
		/// Creates device list of all camera's
		/// </summary>
		public Main()
		{
			InitializeComponent();

			del = new OutputMessageDelegate(OutputMessage);
			
			#region show device list
			try
			{
				// enumerate video devices
				videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
				
				// no cameras? -> go to catch!
				if (videoDevices.Count == 0)
				{
                    camera1Combo.Enabled = false;
                    camera2Combo.Enabled = false;
					throw new Exception();
				}
				
				
				// loop through cameras
				for (int i = 1, n = videoDevices.Count; i <= n; i++)
				{
					string cameraName = i + " : " + videoDevices[i - 1].Name;
					camera1Combo.Items.Add(cameraName);
					camera2Combo.Items.Add(cameraName);
				}

				// Only 1 camera? Disable second!
				if (videoDevices.Count == 1)
				{
					camera2Combo.Items.Clear();
					camera2Combo.Items.Add("Only one camera found");
					camera2Combo.Enabled = false;
					camera2Combo.SelectedIndex = 0;
				}
				else
				{
					camera2Combo.SelectedIndex = 1;
				}
				camera1Combo.SelectedIndex = 0;
			}
			catch
			{
				camera1Combo.Items.Add("No cameras found");
				camera2Combo.Items.Add("No cameras found");

				camera1Combo.SelectedIndex = 0;
				camera2Combo.SelectedIndex = 0;

				camera1Combo.Enabled = false;
				camera2Combo.Enabled = false;
			}
			#endregion
			
			// init dart detector
			dartDetector = new RandomScore();
			dartDetector.Cameras = 2;
			dartDetector.DartDetected += new DartDetectionEventHandler(dartDetector_DartDetected);
		}

		/// <summary>
		/// There is a dart detected and the score was returned
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="score"></param>
		private void dartDetector_DartDetected(object sender, int score)
		{
			string message = "Score: " + score.ToString();
			this.Invoke(del, new object[] { message });
		}

		/// <summary>
		/// Output message to debug textBox
		/// </summary>
		/// <param name="m"></param>
		public void OutputMessage(string m)
		{
			txtConsole.Text = m + Environment.NewLine + txtConsole.Text; 
		}
		
		/// <summary>
		/// Select Camera 1
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void camera1Combo_SelectedIndexChanged(object sender, EventArgs e)
		{
            if (camera1Combo.Enabled == true)
            {
                // stop previous video source
                timer.Stop();
                StopCamera1();

                // create first video source
                VideoCaptureDevice videoSource1 = new VideoCaptureDevice(videoDevices[camera1Combo.SelectedIndex].MonikerString);
                videoSource1.DesiredFrameRate = 10;
                videoSourcePlayer1.VideoSource = videoSource1;
                videoSourcePlayer1.Start();

                // start timer
                timer.Start();
            }
		}

		/// <summary>
		/// Select camera 2
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void camera2Combo_SelectedIndexChanged(object sender, EventArgs e)
		{
			if ( camera2Combo.Enabled == true )
			{
				timer.Stop();
				StopCamera2();
			
				VideoCaptureDevice videoSource2 = new VideoCaptureDevice(videoDevices[camera2Combo.SelectedIndex].MonikerString);
				videoSource2.DesiredFrameRate = 10;
				videoSourcePlayer2.VideoSource = videoSource2;
				videoSourcePlayer2.Start();

				timer.Start();
			}
		}

		/// <summary>
		/// When form is closing, stop cameras
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void Form1_FormClosing(object sender, FormClosingEventArgs e)
		{
			StopCameras();
		}

		#region Stop cameras

		/// <summary>
		/// Stopt alle video sources
		/// </summary>
		private void StopCameras()
		{
			timer.Stop();
			StopCamera1();
			StopCamera2();
		}

		/// <summary>
		/// Stopt video source 1
		/// </summary>
		private void StopCamera1()
		{
			videoSourcePlayer1.SignalToStop();
			videoSourcePlayer1.WaitForStop();
		}

		/// <summary>
		/// Stopt video source 2
		/// </summary>
		private void StopCamera2()
		{
			videoSourcePlayer2.SignalToStop();
			videoSourcePlayer2.WaitForStop();
		}
		#endregion		
		
		#region Events
		
		/// <summary>
		/// Stats timer tick
		/// berekent het aantal fps van de camera's
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void timer_Tick(object sender, EventArgs e)
		{
			IVideoSource videoSource1 = videoSourcePlayer1.VideoSource;
			IVideoSource videoSource2 = videoSourcePlayer2.VideoSource;

			// get number of frames for the last second
			if (videoSource1 != null)
				statCount1[statIndex] = videoSource1.FramesReceived;
			if (videoSource2 != null)
				statCount2[statIndex] = videoSource2.FramesReceived;

			// increment indexes
			if (++statIndex >= statLength)
				statIndex = 0;
			if (statReady < statLength)
				statReady++;

			float fps1 = 0;
			float fps2 = 0;

			// calculate average value
			for (int i = 0; i < statReady; i++)
			{
				fps1 += statCount1[i];
				fps2 += statCount2[i];
			}
			fps1 /= statReady;
			fps2 /= statReady;

			statCount1[statIndex] = 0;
			statCount2[statIndex] = 0;

			camera1GroupBox.Text = string.Format("Camera 1 ({0} fps)", fps1);
			camera2GroupBox.Text = string.Format("Camera 2 ({0} fps)", fps2);
		}
		
		/// <summary>
		/// New frame recieved from video source 1
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="image"></param>
		private void videoSourcePlayer1_NewFrame(object sender, ref Bitmap image)
		{
			dartDetector.ProcessFrame(ref image, 1);
		}
		
		/// <summary>
		/// Frame recieved from video source 2
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="image"></param>
		private void videoSourcePlayer2_NewFrame(object sender, ref Bitmap image)
		{
			dartDetector.ProcessFrame(ref image, 2);
		}

		#endregion
	}
}
